﻿#include "HttpPartParse.h"

HttpPartParse::HttpPartParse(const QByteArray& body)
	:m_body(body)
{
	parse();
}

//用于解析 HTTP 请求体（body）中的form-data 格式的数据:											这个函数每行都做了注释，方便日后理解
bool HttpPartParse::parse()
{
	//查找空行：	用于查找 HTTP 请求正文中的空行，即分隔请求头和请求体的空行的位置
	auto pos = m_body.indexOf("\r\n\r\n");
	//获取头：		获取请求头部分，并去除首尾空格
	auto header = m_body.mid(0, pos + strlen("\r\n\r\n")).trimmed();
	//拆分头：		将请求头部分按换行符拆分成多行，并存储在一个列表中
	auto headers = header.split('\n');
	//获取边界：	获取请求头部分的第一行，通常包含边界信息									边界信息在数据中有两段，一段是数据的开头，一段是数据的结尾
	auto boundary = headers.at(0).trimmed();
	qDebug() << boundary;

	//用于遍历请求头的每一行（除了第一行（边界信息））:
	for (size_t i = 1; i < headers.size(); i++)
	{
		//将请求头的每一行按冒号拆分成键值对，键值对应的是 HTTP 头部的名称和值：
		auto pair = headers.at(i).split(':');
		//将拆分得到的键值对插入到一个m_headers 的map容器中，用于存储 HTTP 请求头的各个字段和对应的值：
		m_headers.insert(pair.first().trimmed(), pair.last().trimmed());
	}
	
	//查找 HTTP 请求头中是否包含 Content-Disposition 字段：
	auto it = m_headers.find("Content-Disposition");
	//如果请求头中没有这个字段，那将无法拿到头像的信息，解析失败：
	if (it == m_headers.end())
	{
		return false;
	}

	//如果包含 Content-Disposition 字段，这行代码将其按	分号	拆分成多个指令:
	auto instructs = it.value().split(';');
	//移除第一个元素:
	instructs.removeFirst();

	//遍历剩余的指令:
	for (const auto& instruct : instructs)
	{
		//将每个指令按	等号	拆分成键值对:
		auto tmp = instruct.split('=');
		//获取键，并去除首尾空格:
		const auto& key = tmp.first().trimmed();
		//获取值，并移除双引号:
		const auto& value = tmp.last().removeIf([](const char& ch) {return ch == '\"'; });

		//http 请求头中的	body的参数名的	值：
		if (key == "name")
		{
			m_parametername = value;
		}
		//http 请求头中的	头像文件名的	值：
		else if (key == "filename")
		{
			m_filename = value;
		}
	}

	//找到请求体的结束位置:						结尾的边界信息
	auto endPos = m_body.lastIndexOf(boundary);

	//获取请求体的数据，并存储到 m_data 中:					请求头部分		与		结尾的边界信息之间		是图片的整个数据了；
	m_data = m_body.mid(pos + 4, endPos - 2 - pos - 4);


	//解析数据成功：
	return true;
}

QByteArray HttpPartParse::header(const QByteArray& key)const
{
	return m_headers.value(key);
}
const QByteArray& HttpPartParse::parameterName()const
{
	return m_parametername;
}
const QByteArray& HttpPartParse::fileName()const
{
	return m_filename;
}
const QByteArray& HttpPartParse::fileData()const
{
	return m_data;
}